package com.lhl.wx.miniapp.config;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Maps;
import com.lhl.wx.miniapp.handler.*;
import com.lhl.wx.miniapp.properties.WxMaProperties;
import lombok.val;
import me.chanjar.weixin.common.error.WxRuntimeException;
import me.chanjar.weixin.common.redis.JedisWxRedisOps;
import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
import me.chanjar.weixin.common.redis.WxRedisOps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @className: com.lhl.wx.miniapp.config.WxMaAutoConfiguration
 * @description: 小程序
 * @author: king
 * @date: 2020-12-16 14:05
 **/
@Configuration
@ConditionalOnClass(WxMaService.class)
@EnableConfigurationProperties(WxMaProperties.class)
@ConditionalOnProperty(prefix = "wx.miniapp", value = "enabled", matchIfMissing = true)
public class WxMaConfiguration {
    private final WxMaProperties wxMaProperties;
    private final ApplicationContext applicationContext;

    private static final Map<String, WxMaMessageRouter> routers = Maps.newHashMap();
    private static Map<String, WxMaService> maServices;

    @Autowired
    public WxMaConfiguration(WxMaProperties wxMaProperties, ApplicationContext applicationContext) {
        this.wxMaProperties = wxMaProperties;
        this.applicationContext = applicationContext;
    }
    /**
     * @param: appId
     * @description: 通过小程序APPID获得WxMaService对象
     * @return: cn.binarywang.wx.miniapp.api.WxMaService
     * @author: king
     * @date: 2020-12-16 14:11
     */
    public static WxMaService getMaService(String appId) {
        WxMaService wxService = maServices.get(appId);
        if (wxService == null) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", appId));
        }

        return wxService;
    }

    /**
     * @param: appId
     * @description: 通过小程序APPID获得对应的消息路由对象
     * @return: cn.binarywang.wx.miniapp.message.WxMaMessageRouter
     * @author: king
     * @date: 2020-12-16 14:12
     */
    public static WxMaMessageRouter getRouter(String appId) {
        return routers.get(appId);
    }

    @PostConstruct
    public void initService() {
        List<WxMaProperties.AppConfig> appConfigs = this.wxMaProperties.getAppConfigs();
        if (CollUtil.isEmpty(appConfigs)) {
            throw new WxRuntimeException("大哥，拜托先看下项目首页的说明（readme文件），添加下相关配置，注意别配错了！");
        }

        maServices = appConfigs.stream()
                .map(a -> {
//                    WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
//                WxMaDefaultConfigImpl config = new WxMaRedisConfigImpl(new JedisPool());
                    // 使用上面的配置时，需要同时引入jedis-lock的依赖，否则会报类无法找到的异常
//                    val configStorage = wxMaConfigStorage("wx:cp:"+a.getAppid());
                    val configStorage = wxMaConfigStorage(a);
                    WxMaService service = new WxMaServiceImpl();
                    service.setWxMaConfig(configStorage);
                    routers.put(a.getAppid(), this.newRouter(service));
                    return service;
                }).collect(Collectors.toMap(s -> s.getWxMaConfig().getAppid(), a -> a));
    }
    private WxMaMessageRouter newRouter(WxMaService service) {
        final WxMaMessageRouter router = new WxMaMessageRouter(service);
        router
                .rule().handler(new LogHandler()).next()
                .rule().async(false).content("订阅消息").handler(new SubscribeHandler()).end()
                .rule().async(false).content("文本").handler(new TextHandler()).end()
                .rule().async(false).content("图片").handler(new PicHandler()).end()
                .rule().async(false).content("二维码").handler(new QrcodeHandler()).end();
        return router;
    }

    private WxMaDefaultConfigImpl wxMaConfigStorage(WxMaProperties.AppConfig appConfig) {
        WxMaDefaultConfigImpl config;
        switch (wxMaProperties.getConfigStorage().getType()) {
            case Jedis:
                config = wxMaJedisConfigStorage("wx:miniApp:"+appConfig.getAppid());
                break;
            case RedisTemplate:
                config = wxMaRedisTemplateConfigStorage("wx:miniApp:"+appConfig.getAppid());
                break;
            default:
                config = wxMaDefaultConfigStorage();
                break;
        }
        config.setAppid(StringUtils.trimToNull(appConfig.getAppid()));
        config.setSecret(StringUtils.trimToNull(appConfig.getSecret()));
        config.setToken(StringUtils.trimToNull(appConfig.getToken()));
        config.setAesKey(StringUtils.trimToNull(appConfig.getAesKey()));
        config.setMsgDataFormat(StringUtils.trimToNull(appConfig.getMsgDataFormat()));

        WxMaProperties.ConfigStorage configStorageProperties = wxMaProperties.getConfigStorage();
        config.setHttpProxyHost(configStorageProperties.getHttpProxyHost());
        config.setHttpProxyUsername(configStorageProperties.getHttpProxyUsername());
        config.setHttpProxyPassword(configStorageProperties.getHttpProxyPassword());
        if (configStorageProperties.getHttpProxyPort() != null) {
            config.setHttpProxyPort(configStorageProperties.getHttpProxyPort());
        }
        return config;
    }

    private WxMaDefaultConfigImpl wxMaDefaultConfigStorage() {
        return new WxMaDefaultConfigImpl();
    }

    private WxMaDefaultConfigImpl wxMaJedisConfigStorage(String keyPrefix) {
        WxMaProperties.RedisProperties redisProperties = wxMaProperties.getConfigStorage().getRedis();
        JedisPool jedisPool;
        if (StringUtils.isNotEmpty(redisProperties.getHost())) {
            JedisPoolConfig config = new JedisPoolConfig();
            if (redisProperties.getMaxActive() != null) {
                config.setMaxTotal(redisProperties.getMaxActive());
            }
            if (redisProperties.getMaxIdle() != null) {
                config.setMaxIdle(redisProperties.getMaxIdle());
            }
            if (redisProperties.getMaxWaitMillis() != null) {
                config.setMaxWaitMillis(redisProperties.getMaxWaitMillis());
            }
            if (redisProperties.getMinIdle() != null) {
                config.setMinIdle(redisProperties.getMinIdle());
            }
            config.setTestOnBorrow(true);
            config.setTestWhileIdle(true);

            jedisPool = new JedisPool(config, redisProperties.getHost(), redisProperties.getPort(),
                    redisProperties.getTimeout(), redisProperties.getPassword(), redisProperties.getDatabase());
        } else {
            jedisPool = applicationContext.getBean(JedisPool.class);
        }
        WxRedisOps redisOps = new JedisWxRedisOps(jedisPool);
        return new WxMaRedisBetterConfigImpl(redisOps, keyPrefix);
    }

    private WxMaDefaultConfigImpl wxMaRedisTemplateConfigStorage(String keyPrefix) {
        StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
        WxRedisOps redisOps = new RedisTemplateWxRedisOps(redisTemplate);
        return new WxMaRedisBetterConfigImpl(redisOps, keyPrefix);
    }
}
